package io.scnb.coupon.calculation.template;

import io.scnb.coupon.calculation.api.beans.Product;
import io.scnb.coupon.calculation.api.beans.ShoppingCart;
import io.scnb.coupon.template.api.beans.CouponTemplateInfo;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public abstract class AbstractRuleTemplate implements RuleTemplate{

    @Override
    public ShoppingCart calculate(ShoppingCart order) {
        // 获取订单总价
        long orderTotalAmount = getTotalPrice(order.getProducts());
        // 获取以shopId为维度的总价统计
        Map<Long, Long> sumAmount = getTotalPriceGroupByShop(order.getProducts());
        CouponTemplateInfo template = order.getCouponInfos().get(0).getTemplate();

        // 最低消费限制
        Long threshold = template.getRule().getDiscount().getThreshold();
        // 优惠金额或者打折比例
        Long quota = template.getRule().getDiscount().getQuota();
        // 如果优惠券没有指定商店，则所有的商品都可以使用
        // 否则，只能对指定商店的商品价格进行优惠
        Long shopId = template.getShopId();
        Long shopTotalAmount = (shopId == null) ? orderTotalAmount : sumAmount.get(shopId);

        // 如果不符合优惠券使用标准，则直接按原价走，不使用优惠券
        if (shopTotalAmount == null || shopTotalAmount < threshold) {
            log.debug("Totals of amount not meet");
            order.setCost(orderTotalAmount);
            order.setCouponInfos(Collections.emptyList());
            return order;
        }
        // 在子类中实现calculateNewPrice计算新的价格
        Long newCost = calculateNewPrice(orderTotalAmount, shopTotalAmount, quota);

        if (newCost < minCost()) {
            newCost = minCost();
        }

        order.setCost(newCost);
        log.debug("original price={}, new price={}", orderTotalAmount, newCost);
        return order;

    }

    // 金额计算具体逻辑，延迟到了子类实现
    abstract protected Long calculateNewPrice(Long orderTotalAmount, Long shopTotalAmount, Long quota);

    // 计算订单总价
    protected long getTotalPrice(List<Product> products) {
        return products.stream()
                .mapToLong(product -> product.getCount() * product.getPrice())
                .sum();
    }

    // 根据门店维度计算每个门店下商品价格
    // key： shopId
    // value：该门店下商品总价
    protected Map<Long, Long> getTotalPriceGroupByShop(List<Product> products) {
        Map<Long, Long> groups = products.stream()
                .collect(
                        Collectors.groupingBy(m -> m.getShopId(),
                        Collectors.summingLong(p -> p.getPrice() * p.getCount()))
                );

        return groups;
    }

    // 每个订单最少必须支付1分钱
    protected long minCost() {
        return 1L;
    }

    protected Long convertToDecimal(Double value) {
        return new BigDecimal(value).setScale(0, RoundingMode.HALF_UP).longValue();
    }

}
